#include "VolumeRenderPCH.h"
#include "DVRPass.h"
#include "DVRMethodsDef.h"

//**************************************************************************************************
//FUNCTION:
void CDVRPass::initV()
{
	m_pCube = std::dynamic_pointer_cast<CCube>(ResourceManager::getGameObjectByName("Cube"));
	m_pVolumeObj = std::dynamic_pointer_cast<CVolumeObj>(ResourceManager::getGameObjectByName("Volume"));
	m_pTFObj = std::dynamic_pointer_cast<CTFObj>(ResourceManager::getGameObjectByName("TF"));

	m_pRayCastTex = __createRayCastTex2D();
	genTexture(m_pRayCastTex);
	m_FBO = genFBO({ m_pRayCastTex });
	ResourceManager::registerSharedData("RayCastTex", m_pRayCastTex);

	m_pShader = std::make_shared<CShader>("shaders/DVR_VS.vert", "shaders/DVR_FS.frag");
	m_pShader->activeShader();
	m_pShader->setIntUniformValue("u_UseGradient", m_pTFObj->isUsingGradient());
	m_pShader->setFloatUniformValue("u_SamplingFactor", ResourceManager::getSharedDataByName<float>("SamplingFactor"));
	m_pShader->setTextureUniformValue("u_TransferFunctionTex", m_pTFObj->getTransferFuncTex());
	m_pShader->setTextureUniformValue("u_VolumeTex", m_pVolumeObj->getVolumeTex());
}

//**************************************************************************************************
//FUNCTION:
void CDVRPass::updateV()
{
#ifdef USING_ALL_METHODS
	if (ResourceManager::getSharedDataByName<EDVRMethod>("DVRMethod") == EDVRMethod::GENERAL_DVR)
#endif
	{
		glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
		glEnable(GL_CULL_FACE);
		glCullFace(GL_BACK);

		//The alpha channel here is set to 0.0f for correctly blending pass2.
		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		m_pShader->activeShader();
		m_pShader->setIntUniformValue("u_UseGradient", m_pTFObj->isUsingGradient());
		m_pShader->setFloatUniformValue("u_SamplingFactor", ResourceManager::getSharedDataByName<float>("SamplingFactor"));

		auto CubeMatrix = m_pCube->getModelMatrix();
		m_pShader->setMat4UniformValue("u_ModelMatrix", glm::value_ptr(CubeMatrix));
		//To get correct CameraPos, CubeMatrix should be scale correspond to Cube scale.
		glm::vec4 CameraInModel = glm::inverse(glm::mat4(glm::scale(CubeMatrix, glm::vec3(2.0)))) * glm::vec4(Camera::getMainCameraPos(), 1.0f);
		glm::vec4 CameraPosInTex = glm::translate(glm::vec3(0.5f)) * CameraInModel;
		m_pShader->setFloatUniformValue("u_CameraPosInTex", CameraPosInTex.x, CameraPosInTex.y, CameraPosInTex.z, CameraPosInTex.w);

		drawCube();

		glDisable(GL_CULL_FACE);
		glBindFramebuffer(GL_FRAMEBUFFER, 0);
	}
}

//**************************************************************************************************
//FUNCTION:
std::shared_ptr<STexture> CDVRPass::__createRayCastTex2D()
{
	auto pRayCastTex = std::make_shared<STexture>();
	pRayCastTex->InternalFormat = GL_RGBA16F;
	pRayCastTex->DataType = GL_FLOAT;
	pRayCastTex->Type4MinFilter = GL_NEAREST;
	pRayCastTex->Type4MagFilter = GL_NEAREST;

	return pRayCastTex;
}
